package com.synergy.stockflow.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.nio.charset.StandardCharsets;
import java.time.Duration;

@Configuration
@EnableCaching
public class RedisConfig {
    /**
     * 配置 RedisTemplate，用于手动操作 Redis（如 set、get、delete 等）
     * <p>
     * 注意：此处使用 {@link GenericJackson2JsonRedisSerializer} 作为 value 序列化器，
     * 与 {@link #redisCacheManager} 中的配置保持一致，避免因序列化不兼容导致的乱码或反序列化失败。
     * <p>
     * 关键配置说明：
     * <ul>
     *     <li>key 和 hashKey 使用 {@link StringRedisSerializer}：确保 Redis key 为可读字符串（UTF-8）</li>
     *     <li>value 和 hashValue 使用 {@link GenericJackson2JsonRedisSerializer}：将 Java 对象序列化为带类型信息的 JSON 字符串</li>
     *     <li>支持泛型对象存储（如 List<T>、Result<T>），反序列化时能正确还原类型</li>
     * </ul>
     * <p>
     * ⚠️ 注意：不要与 Jackson2JsonRedisSerializer 混用，二者序列化格式不兼容！
     * <p>
     * 使用场景示例：
     * <pre>
     * @Autowired
     * private RedisTemplate<String, Object> redisTemplate;
     *
     * // 存储
     * redisTemplate.opsForValue().set("user:1", user);
     *
     * // 读取
     * User user = (User) redisTemplate.opsForValue().get("user:1");
     * </pre>
     *
     * @param connectionFactory Redis 连接工厂（Lettuce）
     * @return 配置好的 RedisTemplate 实例
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // Key 序列化
        StringRedisSerializer keySerializer = new StringRedisSerializer(StandardCharsets.UTF_8);

        // Value 序列化：使用 GenericJackson2JsonRedisSerializer（与 CacheManager 一致）
        GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();

        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setKeySerializer(keySerializer);
        redisTemplate.setHashKeySerializer(keySerializer);
        redisTemplate.setValueSerializer(valueSerializer);
        redisTemplate.setHashValueSerializer(valueSerializer);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    /**
     * 配置 Spring Cache 的缓存管理器（RedisCacheManager）
     * <p>
     * 用于支持 {@link org.springframework.cache.annotation.Cacheable}、
     * {@link org.springframework.cache.annotation.CachePut}、
     * {@link org.springframework.cache.annotation.CacheEvict} 等注解。
     * <p>
     * 关键配置说明：
     * <ul>
     *     <li>缓存 key 使用 {@link StringRedisSerializer}：确保 key 显示为可读字符串（如 "permission::tree"）</li>
     *     <li>缓存 value 使用 {@link GenericJackson2JsonRedisSerializer}：将对象序列化为 JSON 并保留类型信息</li>
     *     <li>所有缓存默认过期时间为 1 小时（可通过 @Cacheable 的 condition 或单独配置覆盖）</li>
     * </ul>
     * <p>
     * ✅ 优点：
     * <ul>
     *     <li>缓存数据在 Redis 中为可读 JSON 格式，便于调试</li>
     *     <li>支持复杂对象（如 Result<List<SysPermission>>）的自动序列化与反序列化</li>
     *     <li>与 redisTemplate 使用相同的 value 序列化器，避免数据格式冲突</li>
     * </ul>
     * <p>
     * 示例使用：
     * <pre>
     * @Cacheable(value = "permission", key = "'tree'")
     * public Result<List<SysPermission>> tree() {
     *     // 方法返回值将自动缓存
     * }
     * </pre>
     *
     * @param connectionFactory Redis 连接工厂（Lettuce）
     * @return 配置好的 RedisCacheManager 实例
     */
    @Bean
    public RedisCacheManager redisCacheManager(LettuceConnectionFactory connectionFactory, RedisTemplate<String, Object> redisTemplate){
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                // 设置 key 序列化方式：使用 UTF-8 字符串，确保 key 可读
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer(StandardCharsets.UTF_8)))
                // 设置 value 序列化方式：使用 JSON + 类型信息，确保反序列化正确
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                // 设置默认缓存过期时间：1小时
                .entryTtl(Duration.ofHours(1));

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .build();
    }
}
